/**
 * @file UP_DMA.c
 * @author PoplarTang (poplar_tang@163.com)
 * @brief
 * @version 0.1
 * @date 2023-05-13
 *
 * @copyright Copyright (c) 2023
 *
 */
#include "UP_DMA.h"
#include "gd32f4xx.h"
#include "systick.h"

/* 串口缓冲区的数据长度 */
#define USART_DMA_RECEIVE_LENGTH 4096

uint8_t g_dma_recv_buff[USART_DMA_RECEIVE_LENGTH]; // 接收缓冲区
uint16_t g_dma_recv_length;                        // 接收数据长度

dma_channel_enum dma_channels[] = {
    DMA_CH0,
    DMA_CH1,
    DMA_CH2,
    DMA_CH3,
    DMA_CH4,
    DMA_CH5,
    DMA_CH6,
    DMA_CH7,
};
dma_subperipheral_enum dma_subperipherals[] = {
    DMA_SUBPERI0,
    DMA_SUBPERI1,
    DMA_SUBPERI2,
    DMA_SUBPERI3,
    DMA_SUBPERI4,
    DMA_SUBPERI5,
    DMA_SUBPERI6,
    DMA_SUBPERI7,
};

// 中断的二维数组
IRQn_Type dma_irqs[2][8] = {
    {DMA0_Channel0_IRQn, DMA0_Channel1_IRQn, DMA0_Channel2_IRQn, DMA0_Channel3_IRQn, DMA0_Channel4_IRQn, DMA0_Channel5_IRQn, DMA0_Channel6_IRQn, DMA0_Channel7_IRQn},
    {DMA1_Channel0_IRQn, DMA1_Channel1_IRQn, DMA1_Channel2_IRQn, DMA1_Channel3_IRQn, DMA1_Channel4_IRQn, DMA1_Channel5_IRQn, DMA1_Channel6_IRQn, DMA1_Channel7_IRQn},
};


void DMA_init(uint32_t dma, uint8_t channel_index, uint8_t subperipheral_select)
{
    /* 配置DMA初始化参数 */
    dma_single_data_parameter_struct dma_init_struct;               // DMA单数据结构体
    dma_init_struct.direction = DMA_PERIPH_TO_MEMORY;               // 外设到内存
    dma_init_struct.periph_addr = (uint32_t)&USART_DATA(USART0); // 外设地址
    dma_init_struct.periph_inc = DMA_PERIPH_INCREASE_DISABLE;       // 外设增长模式->不使用增量模式，为固定模式
    dma_init_struct.memory0_addr = (uint32_t)g_dma_recv_buff;       // 内存地址
    dma_init_struct.memory_inc = DMA_MEMORY_INCREASE_ENABLE;        // 内存增长模式->增量模式
    dma_init_struct.periph_memory_width = DMA_PERIPH_WIDTH_8BIT;    // 一次传输长度8bit
    dma_init_struct.circular_mode = DMA_CIRCULAR_MODE_DISABLE;      // 关闭循环模式
    dma_init_struct.number = USART_DMA_RECEIVE_LENGTH;              // 要传输的数据量
    dma_init_struct.priority = DMA_PRIORITY_ULTRA_HIGH;             // DMA中断优先级->超高优先级

    DMA_init_with_config(dma, channel_index, subperipheral_select, dma_init_struct); // 初始化DMA
}

/**
 * \brief 初始化DMA
 * \param[in] dma DMA 外设 根据用户手册中10.4.1外设握手的外设请求表确定
 *         \arg DMA0: RCU_DMA0
 *         \arg DMA1: RCU_DMA1
 *
 */
void DMA_init_with_config(uint32_t dma,
                          uint8_t channel_index,
                          uint8_t subperipheral_select,
                          dma_single_data_parameter_struct dma_init_struct)
{
    // 根据dma确定rcu_dma
    switch (dma)
    {
    case DMA0:
        rcu_periph_clock_enable(RCU_DMA0); // 开启DMA1时钟
        /* 配置DMA中断优先级 */
        nvic_irq_enable(dma_irqs[0][channel_index], 2, 1);
        break;
    case DMA1:
        rcu_periph_clock_enable(RCU_DMA1); // 开启DMA2时钟
        /* 配置DMA中断优先级 */
        nvic_irq_enable(dma_irqs[1][channel_index], 2, 1);
        break;
    default:
        break;
    }
    dma_channel_enum channel = dma_channels[channel_index];
    dma_subperipheral_enum subperipheral = dma_subperipherals[subperipheral_select];

    dma_deinit(dma, channel); // 初始化DMA通道

    /* 初始化DMA结构体 */
    dma_single_data_mode_init(dma, channel, &dma_init_struct);
    /* 使能通道外设 */
    dma_channel_subperipheral_select(dma, channel, subperipheral); // 0->7 根据用户手册中10.4.1外设握手的外设请求表-通道的二进制确定
    /* 使能DMA通道 */
    dma_channel_enable(dma, channel);
    /* 使能DMA通道中断 */
    dma_interrupt_enable(dma, channel, DMA_CHXCTL_FTFIE);
}

void DMA1_Channel2_IRQHandler(void)
{
    if (dma_interrupt_flag_get(DMA1, DMA_CH2, DMA_INT_FLAG_FTF) == SET) // 传输完成中断
    {
        dma_interrupt_flag_clear(DMA1, DMA_CH2, DMA_INT_FLAG_FTF); // 清中断标志位
    }
}

#if USART0_DMA_ENABLE
void USART0_IRQHandler(void)
{

    if (usart_interrupt_flag_get(USART0, USART_INT_FLAG_IDLE) == SET) // 检测到帧空闲中断
    {
        usart_data_receive(USART0); // 必须要读，读出来的值不能要

        /* 处理DMA接收到的数据 */
        g_dma_recv_length = USART_DMA_RECEIVE_LENGTH - dma_transfer_number_get(DMA1, DMA_CH2); // 计算实际接收的数据长度
        g_dma_recv_buff[g_dma_recv_length] = '\0'; // 数据接收完毕，数组结束标志
        
    	/* 重新设置DMA传输 */
        dma_channel_disable(DMA1, DMA_CH2); // 失能DMA通道
	    DMA_init(DMA1, 2, 4);                     // 重新初始化DMA

        on_dma_data_received(USART0, (char *)g_dma_recv_buff, g_dma_recv_length); // 数据处理函数

        memset(g_dma_recv_buff, 0, g_dma_recv_length); // 清空数组
        g_dma_recv_length = 0;                         // 清空长度
    }
}

#else

// void on_dma_data_received(uint32_t usartx, char *data, uint16_t length){
// }

#endif